/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package testing.jee.web.view;

import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.event.Action;
import com.vaadin.event.MouseEvents;
import com.vaadin.event.MouseEvents.ClickListener;
import com.vaadin.terminal.Sizeable;
import com.vaadin.terminal.ThemeResource;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.DateField;
import com.vaadin.ui.DragAndDropWrapper;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.Label;
import com.vaadin.ui.Link;
import com.vaadin.ui.Panel;
import com.vaadin.ui.Slider;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.TabSheet.SelectedTabChangeEvent;
import com.vaadin.ui.TabSheet.Tab;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.ui.Window.Notification;
import com.vaadin.ui.themes.BaseTheme;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import testing.jee.ejb.RequestBean;
import testing.jee.entity.Timeline;
import testing.jee.entity.Workday;
import testing.jee.entity.Workpackage;
import testing.jee.util.DateUtils;
import testing.jee.util.DurationUtil;
import testing.jee.util.HolidayUtils;
import testing.jee.web.View;

/**
 *
 * @author kreisera
 */
@Component
@Scope(value="session")
public class AssignWorkpackageView extends VerticalLayout implements View {

    @Autowired
    RequestBean req;
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
    SimpleDateFormat longDateFormat = new SimpleDateFormat("E dd.MM.yyyy");
    private final int HOURS_PER_DAY = 8;
    private final int WORKPACKAGES_PER_PAGE = 10;
    VerticalLayout workpackageLayout = new VerticalLayout();
    VerticalLayout timelineLayout = new VerticalLayout();
    @Autowired
    UserSelectorView userSelector;
    Button previous;
    Button next;
    HorizontalLayout filterHori = new HorizontalLayout();
    HorizontalLayout timelineControls = new HorizontalLayout();
    DateField dateSelector = new DateField("Jump to week");
    TabSheet pageTab = new TabSheet();
    private String orderBy = "";
    private String orderDirection = "";
    Date currentStartDate;
    Date today;
    Window splitDialog = new Window("Split Workpackage");
    Window reallyDeleteWindow = new Window("Delete Workpackage");
    Label reallyDeleteLabel = new Label();
    TextField splitField = new TextField("Split at");
    Slider splitSlider = new Slider(1, 2);
    DurationValidator splitValidator = new DurationValidator("Please provide a valid duration greater than zero");
    long splitId;
    long deleteId;
    private int currentPage = 0;
    private boolean tabSheetIsInitialized = false;
    private final static Action deleteAction = new Action("Delete");
    private final static Action[] actionsForWP = new Action[]{deleteAction};

    @PostConstruct
    public void init() {

        initToday();
        currentStartDate = DateUtils.toStartOfWeek(today);

        previous = new Button("Previous Week");
        previous.addListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                currentStartDate = DateUtils.toPreviousWeek(currentStartDate);
                createTimeline();
                getApplication().getMainWindow().showNotification("Showing week " + longDateFormat.format(currentStartDate) + " for " + userSelector.getCurrentUser().getId(), Notification.TYPE_TRAY_NOTIFICATION);
            }
        });
        previous.setWidth("250px");
        next = new Button("Next Week");
        next.addListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                currentStartDate = DateUtils.toNextWeek(currentStartDate);
                createTimeline();
                getApplication().getMainWindow().showNotification("Showing week " + longDateFormat.format(currentStartDate) + " for " + userSelector.getCurrentUser().getId(), Notification.TYPE_TRAY_NOTIFICATION);
            }
        });
        next.setWidth("250px");
        dateSelector.setDateFormat("dd.MM.yyyy");
        dateSelector.setShowISOWeekNumbers(false);
        dateSelector.setResolution(DateField.RESOLUTION_DAY);
        dateSelector.setImmediate(true);
        dateSelector.addListener(new ValueChangeListener() {

            @Override
            public void valueChange(ValueChangeEvent event) {
                currentStartDate = DateUtils.normalize((Date) event.getProperty().getValue(), Calendar.MONDAY);
                createTimeline();
                getApplication().getMainWindow().showNotification("Showing week " + longDateFormat.format(currentStartDate) + " for " + userSelector.getCurrentUser().getId(), Notification.TYPE_TRAY_NOTIFICATION);
            }
        });
        timelineControls.addComponent(userSelector);
        timelineControls.setComponentAlignment(userSelector, Alignment.MIDDLE_LEFT);
        timelineControls.addComponent(dateSelector);
        timelineControls.setComponentAlignment(dateSelector, Alignment.MIDDLE_RIGHT);
        HorizontalSplitPanel horizontalSplitPanel = new HorizontalSplitPanel();
        pageTab.setHeight("750px");
        VerticalLayout workpackageFilterView = new VerticalLayout();
        filterHori.setWidth("100%");
        workpackageFilterView.addComponent(filterHori);
        workpackageFilterView.addComponent(pageTab);
        workpackageFilterView.setComponentAlignment(filterHori, Alignment.MIDDLE_CENTER);
        horizontalSplitPanel.setFirstComponent(workpackageFilterView);
        pageTab.addListener(new TabSheet.SelectedTabChangeListener() {

            @Override
            public void selectedTabChange(SelectedTabChangeEvent event) {
                if (tabSheetIsInitialized) {
                    TabSheet tabsheet = event.getTabSheet();
                    Tab tab = tabsheet.getTab(tabsheet.getSelectedTab());
                    int newpage = tabsheet.getTabPosition(tab);
                    if (tab != null) {
                        currentPage = newpage;
                        createWorkpackagePanels();
                    }
                }
            }
        });
        workpackageLayout.setWidth("95%");
        workpackageLayout.addStyleName("no-horizontal-drag-hints");
        workpackageLayout.addStyleName("no-vertical-drag-hints");
        workpackageLayout.addStyleName("wp-workpackage-list");

        VerticalLayout timeLineControlAndLayout = new VerticalLayout();
        timelineControls.setSpacing(true);
        timeLineControlAndLayout.addComponent(timelineControls);
        timeLineControlAndLayout.addComponent(timelineLayout);
        timeLineControlAndLayout.setSpacing(true);
        
        horizontalSplitPanel.setSecondComponent(timeLineControlAndLayout);
        horizontalSplitPanel.addStyleName("wp-assign-view");
        timelineLayout.addStyleName("no-vertical-drag-hints");
        timelineLayout.addStyleName("no-horizontal-drag-hints");
        timelineLayout.addStyleName("wp-timeline");
        timelineLayout.setWidth("350px");

        createWorkpackagePanels();

        initFilters();

        userSelector.addListener(new ValueChangeListener() {

            @Override
            public void valueChange(ValueChangeEvent event) {
                createTimeline();
                getApplication().getMainWindow().showNotification("Showing week " + longDateFormat.format(currentStartDate) + " for " + userSelector.getCurrentUser().getId(), Notification.TYPE_TRAY_NOTIFICATION);
            }
        });
        addComponent(horizontalSplitPanel);
        addStyleName("wp-assign-view");

        splitDialog.setModal(true);
        splitDialog.setWidth("300px");
        VerticalLayout splitDialogLayout = new VerticalLayout();
        splitDialogLayout.setWidth("250px");
        splitField.setRequired(true);
        splitField.setWidth("150px");
        splitField.setRequiredError("Split amount is required");
        splitField.addValidator(splitValidator);
        splitField.setValidationVisible(true);

        splitDialogLayout.addComponent(splitField);

        splitSlider.setImmediate(true);
        splitSlider.setWidth("150px");
        splitSlider.addListener(new ValueChangeListener() {

            @Override
            public void valueChange(ValueChangeEvent event) {
                splitField.setValue(DurationUtil.serializeDuration(((Double) event.getProperty().getValue()).intValue()));
            }
        });
        splitDialogLayout.addComponent(splitSlider);

        splitDialog.addComponent(splitDialogLayout);

        Button splitButton = new Button("Split!");
        splitButton.addListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                if (splitField.isValid()) {
                    req.splitWorkpackage(DurationUtil.convertToHours((String) splitField.getValue()), splitId);
                    getWindow().removeWindow(splitDialog);
                    createWorkpackagePanels();
                }
            }
        });
        splitDialogLayout.addComponent(splitButton);

        reallyDeleteWindow.setModal(true);
        reallyDeleteWindow.setWidth(300, Sizeable.UNITS_PIXELS);
        VerticalLayout reallyDeleteLayout = new VerticalLayout();
        reallyDeleteLayout.setWidth(250, Sizeable.UNITS_PIXELS);
        Button reallyDeleteButton = new Button("Delete");
        reallyDeleteButton.addListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                String wpName = req.getWorkpackageLabelById(deleteId);
                req.deleteWorkpackage(deleteId);
                createWorkpackagePanels();
                getWindow().removeWindow(reallyDeleteWindow);
                getApplication().getMainWindow().showNotification("Workpackage " + wpName + " deleted.", Notification.TYPE_HUMANIZED_MESSAGE);
            }
        });
        Button cancelDeleteButton = new Button("Cancel");
        cancelDeleteButton.addListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                getWindow().removeWindow(reallyDeleteWindow);
            }
        });
        reallyDeleteLayout.addComponent(reallyDeleteLabel);
        HorizontalLayout deleteDgButtons = new HorizontalLayout();
        deleteDgButtons.addComponent(reallyDeleteButton);
        deleteDgButtons.addComponent(cancelDeleteButton);
        reallyDeleteLayout.addComponent(deleteDgButtons);
        reallyDeleteWindow.addComponent(reallyDeleteLayout);
    }

    @Override
    public void preView() {
        userSelector.update();
        update();
    }

    public void update() {
        createWorkpackagePanels();
        createTimeline();
    }

    private void initToday() {
        today = DateUtils.normalize(new Date());
    }

    private void initFilters() {
        filterHori.setSpacing(true);
        filterHori.setWidth("100%");
        Button sortByDueDateDescButton = new Button();
        sortByDueDateDescButton.addListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                orderBy = "w.dueDate";
                orderDirection = "DESC";
                createWorkpackagePanels();
            }
        });

        Button sortByDueDateAscButton = new Button();
        sortByDueDateAscButton.addListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                orderBy = "w.dueDate";
                orderDirection = "ASC";
                createWorkpackagePanels();
            }
        });

        Button sortByLabelAscButton = new Button();
        sortByLabelAscButton.addListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                orderBy = "w.label";
                orderDirection = "ASC";
                createWorkpackagePanels();
            }
        });

        Button sortByLabelDescButton = new Button();
        sortByLabelDescButton.addListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                orderBy = "w.label";
                orderDirection = "DESC";
                createWorkpackagePanels();
            }
        });

        Button sortByDurationAscButton = new Button();
        sortByDurationAscButton.addListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                orderBy = "w.duration";
                orderDirection = "ASC";
                createWorkpackagePanels();
            }
        });

        Button sortByDurationDescButton = new Button();
        sortByDurationDescButton.addListener(new Button.ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                orderBy = "w.duration";
                orderDirection = "DESC";
                createWorkpackagePanels();
            }
        });
        
        Label sortByDueDateLabel = new Label("Due Date");
        Label sortByDurationLabel = new Label("Duration");
        Label sortByLabelLabel = new Label("Name");
        
        sortByDueDateAscButton.setIcon(new ThemeResource("../runo/icons/16/arrow-up.png"));
        sortByDueDateAscButton.setStyleName(BaseTheme.BUTTON_LINK);
        sortByDueDateDescButton.setIcon(new ThemeResource("../runo/icons/16/arrow-down.png"));
        sortByDueDateDescButton.setStyleName(BaseTheme.BUTTON_LINK);

        sortByLabelAscButton.setIcon(new ThemeResource("../runo/icons/16/arrow-up.png"));
        sortByLabelAscButton.setStyleName(BaseTheme.BUTTON_LINK);
        sortByLabelDescButton.setIcon(new ThemeResource("../runo/icons/16/arrow-down.png"));
        sortByLabelDescButton.setStyleName(BaseTheme.BUTTON_LINK);

        sortByDurationAscButton.setIcon(new ThemeResource("../runo/icons/16/arrow-up.png"));
        sortByDurationAscButton.setStyleName(BaseTheme.BUTTON_LINK);
        sortByDurationDescButton.setIcon(new ThemeResource("../runo/icons/16/arrow-down.png"));
        sortByDurationDescButton.setStyleName(BaseTheme.BUTTON_LINK);
        
        VerticalLayout dueDateArrowsLayout = new VerticalLayout();
        dueDateArrowsLayout.addComponent(sortByDueDateAscButton);
        dueDateArrowsLayout.addComponent(sortByDueDateDescButton);
        HorizontalLayout dueDateLayout = new HorizontalLayout();
        dueDateLayout.addComponent(dueDateArrowsLayout);
        dueDateLayout.addComponent(sortByDueDateLabel);
        dueDateLayout.setComponentAlignment(dueDateArrowsLayout, Alignment.MIDDLE_LEFT);
        dueDateLayout.setComponentAlignment(sortByDueDateLabel, Alignment.MIDDLE_RIGHT);
        
        VerticalLayout durationArrowsLayout = new VerticalLayout();
        durationArrowsLayout.addComponent(sortByDurationAscButton);
        durationArrowsLayout.addComponent(sortByDurationDescButton);
        HorizontalLayout durationLayout = new HorizontalLayout();
        durationLayout.addComponent(durationArrowsLayout);
        durationLayout.addComponent(sortByDurationLabel);
        durationLayout.setComponentAlignment(durationArrowsLayout, Alignment.MIDDLE_LEFT);
        durationLayout.setComponentAlignment(sortByDurationLabel, Alignment.MIDDLE_RIGHT);
        
        VerticalLayout nameArrowsLayout = new VerticalLayout();
        nameArrowsLayout.addComponent(sortByLabelAscButton);
        nameArrowsLayout.addComponent(sortByLabelDescButton);
        HorizontalLayout nameLayout = new HorizontalLayout();
        nameLayout.addComponent(nameArrowsLayout);
        nameLayout.addComponent(sortByLabelLabel);
        nameLayout.setComponentAlignment(nameArrowsLayout, Alignment.MIDDLE_LEFT);
        nameLayout.setComponentAlignment(sortByLabelLabel, Alignment.MIDDLE_RIGHT);

        VerticalLayout sortDueDateVert = new VerticalLayout();
        sortDueDateVert.addComponent(dueDateLayout);

        VerticalLayout sortLabelVert = new VerticalLayout();
        sortLabelVert.addComponent(durationLayout);

        VerticalLayout sortDurationVert = new VerticalLayout();
        sortDurationVert.addComponent(nameLayout);

        filterHori.addComponent(sortDueDateVert);
        filterHori.addComponent(sortDurationVert);
        filterHori.addComponent(sortLabelVert);
    }

    public void createWorkpackagePanels() {
        workpackageLayout.removeAllComponents();
        int i = 0;
        List<Workpackage> workpackages = req.listWorkpackages(orderBy, orderDirection);
        int sizeOfWorkpackages = workpackages.size();
        int pages = sizeOfWorkpackages / WORKPACKAGES_PER_PAGE;
        for (final Workpackage workpackage : workpackages) {
            if (i >= currentPage * WORKPACKAGES_PER_PAGE
                    && i < currentPage * WORKPACKAGES_PER_PAGE + WORKPACKAGES_PER_PAGE) {
                Panel panel = new Panel();
                VerticalLayout content = new VerticalLayout();
                Link title = new Link(workpackage.getLabel(), null);
                title.setWidth("100%");
                title.setDescription(workpackage.getDescription());
                HorizontalLayout linkAndDelButton = new HorizontalLayout();

                Button delButton = new Button();
                delButton.setStyleName(BaseTheme.BUTTON_LINK);
                delButton.setIcon(new ThemeResource("../runo/icons/16/cancel.png"));
                delButton.addListener(new Button.ClickListener() {

                    @Override
                    public void buttonClick(ClickEvent event) {
                        deleteId = workpackage.getId();
                        reallyDeleteLabel.setCaption("Really delete Workpackage " + workpackage.getLabel() + "?");
                        if (reallyDeleteWindow.getParent() == null) {
                            getWindow().addWindow(reallyDeleteWindow);
                        }
                    }
                });

                linkAndDelButton.addComponent(title);
                linkAndDelButton.addComponent(delButton);
                linkAndDelButton.setWidth("100%");
                linkAndDelButton.setComponentAlignment(delButton, Alignment.MIDDLE_RIGHT);
                content.addComponent(linkAndDelButton);
                content.addComponent(new Label(getDuration(workpackage.getDuration())));
                Label dueDateLabel = new Label(dateFormat.format(workpackage.getDueDate()));
                if (today.after(workpackage.getDueDate())) {
                    dueDateLabel.addStyleName("wp-workpackage-overdue");
                }
                content.addComponent(dueDateLabel);
                if (workpackage.getDuration() < 8) {
                    content.getComponent(1).addStyleName("wp-workpackage-small");
                } else if (workpackage.getDuration() <= 16) {
                    content.getComponent(1).addStyleName("wp-workpackage-medium");
                } else {
                    content.getComponent(1).addStyleName("wp-workpackage-big");
                }
                panel.setContent(content);
                int width = workpackage.getDuration() * 30;
                if (width > 300) {
                    width = 300;
                }
                panel.setWidth(width, UNITS_PIXELS);

                panel.addListener(new ClickListener() {

                    @Override
                    public void click(MouseEvents.ClickEvent event) {
                        if (event.isDoubleClick()) {
                            splitId = workpackage.getId();
                            splitSlider.setMax(workpackage.getDuration() - 1);
                            splitValidator.setMaxDuration(workpackage.getDuration() - 1);
                            splitValidator.setErrorMessage("Duration must be between 1 and " + splitValidator.getMaxDuration());
                            if (splitDialog.getParent() == null) {
                                getWindow().addWindow(splitDialog);
                            }
                            splitField.focus();
                        }
                    }
                });
                DragAndDropWrapper dndWrapper = new DragAndDropWrapper(panel);
                dndWrapper.setData(workpackage);
                dndWrapper.setDragStartMode(DragAndDropWrapper.DragStartMode.WRAPPER);
                if (workpackage.getAssocId() != 0) {
                    dndWrapper.setDropHandler(new MergeDropHandler(workpackage.getAssocId(), workpackage.getId(), this));
                }
                dndWrapper.setWidth(width, UNITS_PIXELS);
                workpackageLayout.addComponent(dndWrapper);
            }
            i++;
        }

        tabSheetIsInitialized = false;


        pageTab.removeAllComponents();

        for (int j = 0; j <= pages; j++) {
            if (j == currentPage) {
                pageTab.addComponent(workpackageLayout);
                pageTab.getTab(workpackageLayout).setCaption((j * WORKPACKAGES_PER_PAGE) + " - "
                        + (j * WORKPACKAGES_PER_PAGE + WORKPACKAGES_PER_PAGE));
            } else {
                VerticalLayout lay = new VerticalLayout();
                pageTab.addComponent(lay);
                pageTab.getTab(lay).setCaption((j * WORKPACKAGES_PER_PAGE) + " - "
                        + (j * WORKPACKAGES_PER_PAGE + WORKPACKAGES_PER_PAGE));
            }
        }
        pageTab.setSelectedTab(workpackageLayout);
        tabSheetIsInitialized = true;
    }

    private void createTimeline() {
        timelineLayout.removeAllComponents();
        timelineLayout.addComponent(previous);
        Date startDate = currentStartDate;
        Date endDate = DateUtils.toEndOfWeek(startDate);
        Timeline timeline = req.getTimeline(startDate, endDate, userSelector.getCurrentUser());
        
        for (Date currDate : timeline.getDates()) {
            Workday currWorkday = timeline.getWorkday(currDate);
            Panel panel = new Panel();
            panel.addStyleName("wp-timeline-day");
            if (currDate.equals(today)) {
                panel.addStyleName("wp-timeline-today");
            }
            panel.setWidth("245px");
            panel.setHeight("75px");
            HorizontalLayout assignedWorkpackagesLayout = new HorizontalLayout();
            panel.setContent(assignedWorkpackagesLayout);
            DragAndDropWrapper wrapper = new DragAndDropWrapper(panel);
            for (Workpackage workpackage : currWorkday.getWorkpackages()) {
                Panel assignedPanel = new Panel(workpackage.getLabel());
                final long wpId = workpackage.getId();
                VerticalLayout content = new VerticalLayout();
                content.addComponent(new Label(getDuration(workpackage.getDuration())));
                assignedPanel.setContent(content);
                assignedPanel.setWidth(workpackage.getDuration() * 30 + "px");
                assignedPanel.addStyleName("wp-workpackage-assigned");
                assignedPanel.addListener(new ClickListener() {

                    @Override
                    public void click(MouseEvents.ClickEvent event) {
                        if (event.isDoubleClick()) {
                            req.unassignWorkpackage(wpId);
                            update();
                        }
                    }
                });
                assignedWorkpackagesLayout.addComponent(assignedPanel);
            }
            String caption = longDateFormat.format(currDate);
            if (currWorkday.getHoursLeft() > 0) {
                caption += " - Left: " + currWorkday.getHoursLeft() + "h";
            }
            if (currWorkday.getHoursLeft() > 0 && !currWorkday.isHoliday()) {
                wrapper.setDropHandler(new AssignmentDropHandler(currDate, userSelector.getCurrentUser(), this));
            }
            if (currWorkday.isHoliday()){
                CssLayout holidayLayout = new CssLayout();
                holidayLayout.addComponent(new Label(HolidayUtils.getHolidayName(currWorkday.getDate())));
                panel.setContent(holidayLayout);
            }
            panel.setCaption(caption);
            wrapper.setWidth("245px");
            timelineLayout.addComponent(wrapper);
        }
        timelineLayout.addComponent(next);
    }

    private String getDuration(int duration) {
        int days = duration / HOURS_PER_DAY;
        int restHours = duration % HOURS_PER_DAY;
        String serializedDuration = "";
        if (days > 0) {
            serializedDuration += (days + "d");
        }
        if (restHours > 0) {
            if (days > 0) {
                serializedDuration += " ";
            }
            serializedDuration += (restHours + "h");
        }
        return serializedDuration;
    }

    @Override
    public void postView() {
    }
}
